<template>
  <transition name="expand" mode="out-in" v-bind="$props" :css="false" @before-appear="beforeAppear" @appear="appear"
    @after-appear="afterAppear" @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"
    @before-leave="beforeLeave" @leave="leave" @after-leave="afterLeave">
    <slot></slot>
  </transition>
</template>

<script>
  // const duration = 250 // ms.
  import { ref, reactive, computed } from "vue";
  export default {
    name: "w-transition-expand",

    props: {
      x: { type: Boolean },
      y: { type: Boolean },
      duration: { type: Number, default: 200 }
    },
    setup(props, ctx) {
      const el = reactive({
        originalStyles: "",
        width: 0,
        height: 0,
        marginLeft: 0,
        marginRight: 0,
        marginTop: 0,
        marginBottom: 0,
        paddingLeft: 0,
        paddingRight: 0,
        paddingTop: 0,
        paddingBottom: 0,
        borderLeftWidth: 0,
        borderRightWidth: 0,
        borderTopWidth: 0,
        borderBottomWidth: 0
      });
      const cleanTransitionCycle = ref(true);

      const animX = computed(() => {
        return props.x || !props.y;
      });
      const animY = computed(() => {
        return props.y || !props.x;
      });

      function beforeAppear(el) {
        // Only save original state once before a 'clean' transition start.
        // Not when clicking very fast and mixing states order.
        if (cleanTransitionCycle.value) {
          saveOriginalStyles(el);
        }
        cleanTransitionCycle.value = false;
      }
      function appear(el, done) {
        show(el);
        setTimeout(done, props.duration);
        cleanTransitionCycle.value = false;
      }
      function afterAppear(el) {
        applyOriginalStyles(el);
        // May be transitioning with v-show, if so don't reapply display none.
        el.style.cssText = el.style.cssText.replace("display: none;", "");
        cleanTransitionCycle.value = false;
      }
      function beforeEnter(el) {
        // Only save original state once before a 'clean' transition start.
        // Not when clicking very fast and mixing states order.
        if (cleanTransitionCycle.value) {
          saveOriginalStyles(el);
        }
        cleanTransitionCycle.value = false;
      }
      function enter(el, done) {
        show(el);
        setTimeout(done, props.duration);
        cleanTransitionCycle.value = false;
      }
      function afterEnter(el) {
        applyOriginalStyles(el);
        // May be transitioning with v-show, if so don't reapply display none.
        el.style.cssText = el.style.cssText.replace("display: none;", "");
        cleanTransitionCycle.value = false;
      }
      function beforeLeave(el) {
        beforeHide(el);
        cleanTransitionCycle.value = false;
      }
      function leave(el, done) {
        hide(el);
        setTimeout(done, props.duration);
        cleanTransitionCycle.value = false;
      }
      function afterLeave(el) {
        applyOriginalStyles(el);
        cleanTransitionCycle.value = true;
      }

      function applyHideStyles(el) {
        if (animX.value) {
          el.style.width = 0;
          el.style.marginLeft = 0;
          el.style.marginRight = 0;
          el.style.paddingLeft = 0;
          el.style.paddingRight = 0;
          el.style.borderLeftWidth = 0;
          el.style.borderRightWidth = 0;
        }
        if (animY.value) {
          el.style.height = 0;
          el.style.marginTop = 0;
          el.style.marginBottom = 0;
          el.style.paddingTop = 0;
          el.style.paddingBottom = 0;
          el.style.borderTopWidth = 0;
          el.style.borderBottomWidth = 0;
        }

        el.style.overflow = "hidden";
      }
      function applyShowStyles(el) {
        if (animX.value) {
          el.style.width = el.width + "px";
          el.style.marginLeft = el.marginLeft;
          el.style.marginRight = el.marginRight;
          el.style.paddingLeft = el.paddingLeft;
          el.style.paddingRight = el.paddingRight;
          el.style.borderLeftWidth = el.borderLeftWidth;
          el.style.borderRightWidth = el.borderRightWidth;
        }
        if (animY.value) {
          el.style.height = el.height + "px";
          el.style.marginTop = el.marginTop;
          el.style.marginBottom = el.marginBottom;
          el.style.paddingTop = el.paddingTop;
          el.style.paddingBottom = el.paddingBottom;
          el.style.borderTopWidth = el.borderTopWidth;
          el.style.borderBottomWidth = el.borderBottomWidth;
        }

        el.style.transition = props.duration + "ms ease-in-out";
      }
      function applyOriginalStyles(el) {
        el.style.cssText = el.originalStyles;
      }
      function saveOriginalStyles(el) {
        // Keep the original styles to restore them after transition.
        el.originalStyles = el.style.cssText;
      }
      function show(el, done) {
        const computedStyles = window.getComputedStyle(el, null);

        // Save the width & height then set them to 0 as the animation starting point.
        if (animX.value) {
          el.width = el.offsetWidth;
          el.marginLeft = computedStyles.getPropertyValue("marginLeft");
          el.marginRight = computedStyles.getPropertyValue("marginRight");
          el.paddingLeft = computedStyles.getPropertyValue("paddingLeft");
          el.paddingRight = computedStyles.getPropertyValue("paddingRight");
          el.borderLeftWidth = computedStyles.getPropertyValue(
            "borderLeftWidth"
          );
          el.borderRightWidth = computedStyles.getPropertyValue(
            "borderRightWidth"
          );
        }
        if (animY.value) {
          el.height = el.offsetHeight;
          el.marginTop = computedStyles.getPropertyValue("marginTop");
          el.marginBottom = computedStyles.getPropertyValue("marginBottom");
          el.paddingTop = computedStyles.getPropertyValue("paddingTop");
          el.paddingBottom = computedStyles.getPropertyValue(
            "paddingBottom"
          );
          el.borderTopWidth = computedStyles.getPropertyValue(
            "borderTopWidth"
          );
          el.borderBottomWidth = computedStyles.getPropertyValue(
            "borderBottomWidth"
          );
        }
        applyHideStyles(el);

        setTimeout(() => applyShowStyles(el), 20);
        setTimeout(done, props.duration);
      }
      function beforeHide(el) {
        applyShowStyles(el);
      }
      function hide(el, done) {
        setTimeout(() => applyHideStyles(el), 20);
        setTimeout(done, props.duration);
      }

      return {
        el,
        cleanTransitionCycle,
        animX,
        animY,
        //computed
        beforeAppear,
        appear,
        afterAppear,
        beforeEnter,
        enter,
        afterEnter,
        beforeLeave,
        leave,
        afterLeave,
        applyHideStyles,
        applyShowStyles,
        applyOriginalStyles,
        saveOriginalStyles,
        show,
        beforeHide,
        hide
      };
    }
    // data: () => ({
    //   el: {
    //     originalStyles: "",
    //     width: 0,
    //     height: 0,
    //     marginLeft: 0,
    //     marginRight: 0,
    //     marginTop: 0,
    //     marginBottom: 0,
    //     paddingLeft: 0,
    //     paddingRight: 0,
    //     paddingTop: 0,
    //     paddingBottom: 0,
    //     borderLeftWidth: 0,
    //     borderRightWidth: 0,
    //     borderTopWidth: 0,
    //     borderBottomWidth: 0
    //   },
    //   cleanTransitionCycle: true
    // }),

    // computed: {
    //   animX() {
    //     return this.x || !this.y;
    //   },
    //   animY() {
    //     return this.y || !this.x;
    //   }
    // },

    // methods: {
    //   beforeAppear(el) {
    //     // Only save original state once before a 'clean' transition start.
    //     // Not when clicking very fast and mixing states order.
    //     if (this.cleanTransitionCycle) this.saveOriginalStyles(el);
    //     this.cleanTransitionCycle = false;
    //   },
    //   appear(el, done) {
    //     this.show(el);
    //     setTimeout(done, this.duration);
    //     this.cleanTransitionCycle = false;
    //   },
    //   afterAppear(el) {
    //     this.applyOriginalStyles(el);
    //     // May be transitioning with v-show, if so don't reapply display none.
    //     el.style.cssText = el.style.cssText.replace("display: none;", "");
    //     this.cleanTransitionCycle = false;
    //   },
    //   beforeEnter(el) {
    //     // Only save original state once before a 'clean' transition start.
    //     // Not when clicking very fast and mixing states order.
    //     if (this.cleanTransitionCycle) this.saveOriginalStyles(el);
    //     this.cleanTransitionCycle = false;
    //   },
    //   enter(el, done) {
    //     this.show(el);
    //     setTimeout(done, this.duration);
    //     this.cleanTransitionCycle = false;
    //   },
    //   afterEnter(el) {
    //     this.applyOriginalStyles(el);
    //     // May be transitioning with v-show, if so don't reapply display none.
    //     el.style.cssText = el.style.cssText.replace("display: none;", "");
    //     this.cleanTransitionCycle = false;
    //   },
    //   beforeLeave(el) {
    //     this.beforeHide(el);
    //     this.cleanTransitionCycle = false;
    //   },
    //   leave(el, done) {
    //     this.hide(el);
    //     setTimeout(done, this.duration);
    //     this.cleanTransitionCycle = false;
    //   },
    //   afterLeave(el) {
    //     this.applyOriginalStyles(el);
    //     this.cleanTransitionCycle = true;
    //   },

    //   applyHideStyles(el) {
    //     if (this.animX) {
    //       el.style.width = 0;
    //       el.style.marginLeft = 0;
    //       el.style.marginRight = 0;
    //       el.style.paddingLeft = 0;
    //       el.style.paddingRight = 0;
    //       el.style.borderLeftWidth = 0;
    //       el.style.borderRightWidth = 0;
    //     }
    //     if (this.animY) {
    //       el.style.height = 0;
    //       el.style.marginTop = 0;
    //       el.style.marginBottom = 0;
    //       el.style.paddingTop = 0;
    //       el.style.paddingBottom = 0;
    //       el.style.borderTopWidth = 0;
    //       el.style.borderBottomWidth = 0;
    //     }

    //     el.style.overflow = "hidden";
    //   },
    //   applyShowStyles(el) {
    //     if (this.animX) {
    //       el.style.width = this.el.width + "px";
    //       el.style.marginLeft = this.el.marginLeft;
    //       el.style.marginRight = this.el.marginRight;
    //       el.style.paddingLeft = this.el.paddingLeft;
    //       el.style.paddingRight = this.el.paddingRight;
    //       el.style.borderLeftWidth = this.el.borderLeftWidth;
    //       el.style.borderRightWidth = this.el.borderRightWidth;
    //     }
    //     if (this.animY) {
    //       el.style.height = this.el.height + "px";
    //       el.style.marginTop = this.el.marginTop;
    //       el.style.marginBottom = this.el.marginBottom;
    //       el.style.paddingTop = this.el.paddingTop;
    //       el.style.paddingBottom = this.el.paddingBottom;
    //       el.style.borderTopWidth = this.el.borderTopWidth;
    //       el.style.borderBottomWidth = this.el.borderBottomWidth;
    //     }

    //     el.style.transition = this.duration + "ms ease-in-out";
    //   },
    //   applyOriginalStyles(el) {
    //     el.style.cssText = this.el.originalStyles;
    //   },
    //   saveOriginalStyles(el) {
    //     // Keep the original styles to restore them after transition.
    //     this.el.originalStyles = el.style.cssText;
    //   },
    //   show(el, done) {
    //     const computedStyles = window.getComputedStyle(el, null);

    //     // Save the width & height then set them to 0 as the animation starting point.
    //     if (this.animX) {
    //       this.el.width = el.offsetWidth;
    //       this.el.marginLeft = computedStyles.getPropertyValue("marginLeft");
    //       this.el.marginRight = computedStyles.getPropertyValue("marginRight");
    //       this.el.paddingLeft = computedStyles.getPropertyValue("paddingLeft");
    //       this.el.paddingRight = computedStyles.getPropertyValue("paddingRight");
    //       this.el.borderLeftWidth = computedStyles.getPropertyValue(
    //         "borderLeftWidth"
    //       );
    //       this.el.borderRightWidth = computedStyles.getPropertyValue(
    //         "borderRightWidth"
    //       );
    //     }
    //     if (this.animY) {
    //       this.el.height = el.offsetHeight;
    //       this.el.marginTop = computedStyles.getPropertyValue("marginTop");
    //       this.el.marginBottom = computedStyles.getPropertyValue("marginBottom");
    //       this.el.paddingTop = computedStyles.getPropertyValue("paddingTop");
    //       this.el.paddingBottom = computedStyles.getPropertyValue(
    //         "paddingBottom"
    //       );
    //       this.el.borderTopWidth = computedStyles.getPropertyValue(
    //         "borderTopWidth"
    //       );
    //       this.el.borderBottomWidth = computedStyles.getPropertyValue(
    //         "borderBottomWidth"
    //       );
    //     }
    //     this.applyHideStyles(el);

    //     setTimeout(() => this.applyShowStyles(el), 20);
    //     setTimeout(done, this.duration);
    //   },
    //   beforeHide(el) {
    //     this.applyShowStyles(el);
    //   },
    //   hide(el, done) {
    //     setTimeout(() => this.applyHideStyles(el), 20);
    //     setTimeout(done, this.duration);
    //   }
    // }
  };
</script>